package com.im;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler.Callback;
import android.os.Message;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;

import com.common.InputBox;

import java.util.List;
import java.util.Objects;

// 主活动
public class MainActivity extends AppCompatActivity implements Callback,
    InputBox.Callback, LogonDialog.Callback, OnItemClickListener, OnMenuItemClickListener {
    private Client mClient;                 // 客户端
    private TextView mLabelFriendCount;     // "好友数"标签
    private TextView mLabelStatus;          // "登录状态"标签
    private UserListView mListViewUsers;    // 好友列表控件
    private MenuItem mMenuItemAddFriend;    // "添加好友"菜单项
    private MenuItem mMenuItemLogoff;       // "离线"菜单项
    private MenuItem mMenuItemLogon;        // "登录"菜单项
    private MenuItem mMenuItemMChat;        // "群发消息"菜单项
    private MenuItem mMenuItemReg;          // "注册"菜单项

    /**
     * 添加所有好友到好友列表控件中。
     * @param result    登录结果
     */
    private void addAllFriends(LogonResult result) {
        for (int i = 0; i < result.mFriendCount; i++) {
            this.addOneFriend(result.mFriends.get(i).mUsername, result.mFriends.get(i).mIconIndex, result.mFriendsOnline.get(i));
        }

        mLabelFriendCount.setText(super.getString(R.string.IDS_FRIEND_COUNT, result.mFriendCount));
    }

    /**
     * 添加一个好友到好友列表控件中。
     * @param friendName    好友名
     * @param iconIndex     好友头像索引
     * @param isOnline      好友在线则为 true，否则为 false
     */
    private void addOneFriend(String friendName, int iconIndex, boolean isOnline) {
        if (iconIndex < 0) {
            return;
        }
        mListViewUsers.addItem(friendName, iconIndex, isOnline);
    }

    /**
     * 改变界面状态。
     * @param isLogon   已登录则为 true，否则为 false
     */
    private void changeState(boolean isLogon) {
        mMenuItemLogon.setEnabled(!isLogon);
        mMenuItemReg.setEnabled(!isLogon);
        mMenuItemAddFriend.setEnabled(isLogon);
        mMenuItemMChat.setEnabled(isLogon);
        mMenuItemLogoff.setEnabled(isLogon);

        if (isLogon) {
            mLabelStatus.setText(R.string.IDS_STATUS_LOGON);
        } else {
            mLabelStatus.setText(R.string.IDS_STATUS_LOGOFF);
        }
        mLabelFriendCount.setText(super.getString(R.string.IDS_FRIEND_COUNT, 0));
    }

    /**
     * 获取结果信息。
     * @param resultCode    结果码
     * @return 结果信息
     */
    private String getResultMessage(ResultCode resultCode) {
        switch (resultCode) {
            case ADD_FRIEND_ALLOW:
                return super.getString(R.string.IDS_ADD_FRIEND_ALLOW);
            case ADD_FRIEND_NOT_ALLOW:
                return super.getString(R.string.IDS_ADD_FRIEND_NOT_ALLOW);
            case ALREADY_BE_FRIENDS:
                return super.getString(R.string.IDS_ALREADY_BE_FRIENDS);
            case FRIEND_NAME_EQUAL_SELF_NAME:
                return super.getString(R.string.IDS_FRIEND_NAME_EQUAL_SELF_NAME);
            case LOGON_SUCCEEDED:
                return super.getString(R.string.IDS_LOGON_SUCCEEDED);
            case NETWORK_ERROR:
                return super.getString(R.string.IDS_NETWORK_ERROR);
            case PASSWORD_WRONG:
                return super.getString(R.string.IDS_PASSWORD_WRONG);
            case REG_SUCCEEDED:
                return super.getString(R.string.IDS_REG_SUCCEEDED);
            case TOO_MANY_FRIENDS:
                return super.getString(R.string.IDS_TOO_MANY_FRIENDS);
            case USER_ALREADY_LOGON:
                return super.getString(R.string.IDS_USER_ALREADY_LOGON);
            case USER_EXISTS:
                return super.getString(R.string.IDS_USER_EXISTS);
            case USER_NOT_FOUND:
                return super.getString(R.string.IDS_USER_NOT_FOUND);
        }

        return "";
    }

    /**
     * 处理自定义事件的方法。
     * @param message   事件
     * @return 事件在此被处理则返回 true，否则返回 false
     */
    @Override
    public boolean handleMessage(Message message) {
        switch (message.what) {
            case Const.UM_CHAT_C2S:
                mClient.chat((ChatInfo)message.obj);
                return true;
            case Const.UM_CHAT_S2C:
                this.onChatS2C((ChatInfo)message.obj);
                return true;
            case Const.UM_FRIEND_LOGOFF:
                this.onFriendLogoff((LogoffRequest)message.obj);
                return true;
            case Const.UM_FRIEND_LOGON:
                this.onFriendLogon((FriendLogon)message.obj);
                return true;
            case Const.UM_GET_ADD_FRIEND_REQUEST:
                this.onGetAddFriendRequest((AddFriendRequest)message.obj);
                return true;
            case Const.UM_GET_ADD_FRIEND_RESULT:
                this.onGetAddFriendResult((AddFriendResult)message.obj);
                return true;
            case Const.UM_GET_LOGON_RESULT:
                this.onGetLogonResult((LogonResult)message.obj);
                return true;
            case Const.UM_GET_REG_RESULT:
                this.onGetRegResult((RegResult)message.obj);
                return true;
            case Const.UM_NETWORK_ERROR:
                new AlertDialog.Builder(this)
                    .setCancelable(false)
                    .setMessage(R.string.IDS_NETWORK_ERROR)
                    .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> System.exit(0))
                    .show();
                return true;
        }
        return false;
    }

    /**
     * Activity 返回结果事件的响应方法。
     * @param requestCode   请求码
     * @param resultCode    结果码
     * @param intent        数据
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        if (resultCode != Activity.RESULT_OK) {
            return;
        }

        // 获取数据
        final Bundle bundle = intent.getExtras();

        // 根据请求码，做相应处理
        if (requestCode == Const.RC_REG) {
            assert bundle != null;
            final String username = bundle.getString(Const.KEY_USERNAME);
            final String password = bundle.getString(Const.KEY_PASSWORD);
            final int iconIndex = bundle.getInt(Const.KEY_ICON_INDEX);
            mClient.reg(username, password, iconIndex);
        }

        super.onActivityResult(requestCode, resultCode, intent);
    }

    /**
     * 聊天事件的响应方法（服务器到客户端）。
     * @param chatInfo  聊天信息
     */
    private void onChatS2C(ChatInfo chatInfo) {
        // 获取当前屏幕上显示的窗口的名称
        final ActivityManager activityManager = (ActivityManager)super.getSystemService(Context.ACTIVITY_SERVICE);
        final List<ActivityManager.RunningTaskInfo> runningTaskInfoList = activityManager.getRunningTasks(1);
        String topActivityName = null;
        if (runningTaskInfoList != null) {
            topActivityName = Objects.requireNonNull(runningTaskInfoList.get(0).topActivity).getClassName();
        }

        // 获取好友名
        final boolean isMultiChat = chatInfo.mDstUsername.equals(ImProtocol.MULTI_CHAT);
        final String friendName = isMultiChat ? chatInfo.mDstUsername: chatInfo.mSrcUsername;

        // 生成意图
        final Intent intent = new Intent(this, ChatActivity.class);
        intent.putExtra(Const.KEY_CHAT_INFO, chatInfo);

        if (ChatActivity.class.getName().equals(topActivityName) && ChatActivity.getFriendName().equals(friendName)) {
            // 如果聊天窗口在屏幕上，并且发送聊天信息的好友是当前聊天窗口的好友，则直接显示聊天信息
            super.startActivity(intent);
        } else {
            // 发送通知
            // 创建系统通知
            final PendingIntent pendingIntent = PendingIntent.getActivity(this,
                Const.UM_CHAT_S2C, intent, PendingIntent.FLAG_UPDATE_CURRENT);
            final String title = isMultiChat ? chatInfo.mSrcUsername + " [ " + ImProtocol.MULTI_CHAT + " ]": chatInfo.mSrcUsername;
            final Notification notification = new Notification.Builder(this, Const.INTENT_CHAT_S2C)
                .setAutoCancel(true)
                .setContentTitle(title)
                .setContentText(chatInfo.mContent)
                .setSmallIcon(chatInfo.mSrcIconIndex + R.mipmap.normal00)
                .setContentIntent(pendingIntent)
                .build();

            // 发送通知，即在系统的通知栏上显示通知
            final NotificationManager manager = (NotificationManager)super.getSystemService(Context.NOTIFICATION_SERVICE);
            final NotificationChannel channel = new NotificationChannel(Const.INTENT_CHAT_S2C, ChatActivity.class.getName(), NotificationManager.IMPORTANCE_HIGH);
            manager.createNotificationChannel(channel);
            manager.notify(Const.NOTIFICATION_ID_CHAT, notification);
        }
    }

    /**
     * 创建事件的响应方法。
     * @param savedInstanceState    保存的实例状态
     */
    @SuppressLint("MissingSuperCall")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.setContentView(R.layout.activity_main);

        // 初始化成员
        mClient = new Client(this);
        mLabelFriendCount = super.findViewById(R.id.IDC_LABEL_FRIEND_COUNT);
        mLabelFriendCount.setText(super.getString(R.string.IDS_FRIEND_COUNT, 0));
        mLabelStatus = super.findViewById(R.id.IDC_LABEL_STATUS);
        mListViewUsers = super.findViewById(R.id.IDC_LIST_VIEW_USERS);
        mListViewUsers.setOnItemClickListener(this);
        mListViewUsers.setVerticalSpacing(Const.USER_LIST_VIEW_ITEM_PADDING);

        // 注册广播接收者，用来接收聊天窗口发送的聊天信息
        ContextCompat.registerReceiver(this, new BroadcastReceiver() {
            /**
             * 接收到广播事件的响应方法。
             * @param context 设备环境
             * @param intent  意图
             */
            @Override
            public void onReceive(Context context, Intent intent) {
                final ChatInfo chatInfo = (ChatInfo) intent.getSerializableExtra(ChatInfo.class.getName());
                mClient.chat(chatInfo);
            }
        }, new IntentFilter(Const.INTENT_CHAT_C2S), ContextCompat.RECEIVER_NOT_EXPORTED);

        // 暂停，等所有后台线程阻塞再继续执行
        // 如果此处不暂停，有可能导致无法登录
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建菜单事件的响应方法。
     * @param menu  菜单
     * @return 总是 true
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.getMenuInflater().inflate(R.menu.main, menu);

        // 创建菜单项
        mMenuItemLogon = menu.findItem(R.id.IDC_MENU_ITEM_LOGON);
        mMenuItemReg = menu.findItem(R.id.IDC_MENU_ITEM_REG);
        mMenuItemAddFriend = menu.findItem(R.id.IDC_MENU_ITEM_ADD_FRIEND);
        mMenuItemMChat = menu.findItem(R.id.IDC_MENU_ITEM_MCHAT);
        mMenuItemLogoff = menu.findItem(R.id.IDC_MENU_ITEM_LOGOFF);

        // 菜单项添加事件监听者
        mMenuItemLogon.setOnMenuItemClickListener(this);
        mMenuItemReg.setOnMenuItemClickListener(this);
        mMenuItemAddFriend.setOnMenuItemClickListener(this);
        mMenuItemMChat.setOnMenuItemClickListener(this);
        mMenuItemLogoff.setOnMenuItemClickListener(this);

        return true;
    }

    /**
     * 销毁事件的响应方法。
     */
    @Override
    protected void onDestroy() {
        // 关闭客户端
        mClient.close();

        super.onDestroy();
    }

    /**
     * 好友离线事件的响应方法。
     * @param request   离线请求
     */
    private void onFriendLogoff(LogoffRequest request) {
        mListViewUsers.changeItemColor(request.mUsername, false);
    }

    /**
     * 好友登录事件的响应方法。
     * @param friendLogon   好友登录信息
     */
    private void onFriendLogon(FriendLogon friendLogon) {
        mListViewUsers.changeItemColor(friendLogon.mUsername, true);
    }

    /**
     * 得到添加好友请求事件的响应方法。
     * @param request   添加好友请求
     */
    private void onGetAddFriendRequest(final AddFriendRequest request) {
        final String message = request.mSrcUsername + super.getString(R.string.IDS_CONFIRM_ADD_FRIEND);
        final OnClickListener listener = new OnClickListener() {
            /**
             * 所有按钮的单击响应方法。
             * @param dialog        对话框
             * @param clickedButton 按钮索引
             */
            @Override
            public void onClick(DialogInterface dialog, int clickedButton) {
                final boolean allow = clickedButton == AlertDialog.BUTTON_POSITIVE;
                mClient.allowAddFriend(allow, request);
                if (allow) {
                    MainActivity.this.addOneFriend(request.mSrcUsername, request.mSrcIconIndex, true);
                    mLabelFriendCount.setText(MainActivity.super.getString(R.string.IDS_FRIEND_COUNT, mClient.getFriendCount()));
                }
            }
        };
        new AlertDialog.Builder(this)
            .setCancelable(false)
            .setMessage(message)
            .setPositiveButton(android.R.string.yes, listener)
            .setNegativeButton(android.R.string.no, listener)
            .show();
    }

    /**
     * 得到添加好友结果事件的响应方法。
     * @param result    添加好友结果
     */
    private void onGetAddFriendResult(AddFriendResult result) {
        String message = this.getResultMessage(result.mResultCode);
        if (result.mResultCode == ResultCode.ADD_FRIEND_ALLOW) {
            this.addOneFriend(result.mDstUsername, result.mDstIconIndex, true);
            mLabelFriendCount.setText(super.getString(R.string.IDS_FRIEND_COUNT, mClient.getFriendCount()));
            message = String.format(message, result.mDstUsername);
            Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
        } else if (result.mResultCode == ResultCode.ALREADY_BE_FRIENDS ||
            result.mResultCode == ResultCode.ADD_FRIEND_NOT_ALLOW ||
            result.mResultCode == ResultCode.USER_NOT_FOUND) {
            message = result.mDstUsername + message;
            Toast.makeText(this, message, Toast.LENGTH_LONG).show();
        }
    }

    /**
     * 得到登录结果事件的响应方法。
     * @param result    登录结果
     */
    private void onGetLogonResult(LogonResult result) {
        if (result.mResultCode == ResultCode.LOGON_SUCCEEDED) {
            this.changeState(true);
            this.addAllFriends(result);
        } else {
            final String message = this.getResultMessage(result.mResultCode);
            Toast.makeText(this, message, Toast.LENGTH_LONG).show();
        }
    }

    /**
     * 得到注册结果事件的响应方法。
     * @param result    注册结果
     */
    private void onGetRegResult(RegResult result) {
        final String message = this.getResultMessage(result.mResultCode);
        if (result.mResultCode == ResultCode.REG_SUCCEEDED) {
            this.changeState(true);
            Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, message, Toast.LENGTH_LONG).show();
        }
    }

    @Override
    public void onInputBoxCancel() {
    }

    @Override
    public void onInputBoxOK(int intValue) {
    }

    /**
     * 输入窗口的"确定"按钮的单击响应方法。
     * @param stringValue   用户输入的文字
     */
    @Override
    public void onInputBoxOK(String stringValue) {
        if (TextUtils.isEmpty(stringValue)) {
            return;
        }
        final ResultCode resultCode = mClient.addFriend(stringValue);
        if (resultCode != ResultCode.SUCCEEDED) {
            final String message = this.getResultMessage(resultCode);
            Toast.makeText(this, message, Toast.LENGTH_LONG).show();
        }
    }

    /**
     * 单击好友列表控件的响应方法。
     * @param arg0      没用
     * @param listView  好友列表控件
     * @param item      被单击的表项的索引
     * @param arg3      没用
     */
    @Override
    public void onItemClick(AdapterView<?> arg0, View listView, int item, long arg3) {
        // 取消系统通知
        final NotificationManager manager = (NotificationManager)super.getSystemService(Context.NOTIFICATION_SERVICE);
        manager.cancel(Const.NOTIFICATION_ID_CHAT);

        // 获取用户单击的好友名
        final String friendName = mListViewUsers.getItemText(item);

        // 生成意图
        final Intent intent = new Intent(this, ChatActivity.class);

        // 将好友名保存到意图中
        intent.putExtra(Const.KEY_FRIEND_NAME, friendName);

        // 显示聊天窗口
        super.startActivityForResult(intent, Const.UM_CHAT_C2S);
    }

    /**
     * 按键事件的响应方法。
     * @param keyCode   按键
     * @param e         事件相关信息
     * @return 事件在此被处理则返回 true，否则返回 false
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent e) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            super.moveTaskToBack(false);
            return true;
        }
        return super.onKeyDown(keyCode, e);
    }

    /**
     * 登录窗口的"确定"按钮的单击响应方法。
     * @param username  用户输入的用户名
     * @param password  用户输入的密码
     */
    @Override
    public void onLogonDialogOK(String username, String password) {
        mClient.logon(username, password);
    }

    /**
     * "添加好友"菜单项的单击响应方法。
     */
    private void onMenuItemAddFriendClicked() {
        final String tipText = super.getString(R.string.IDS_PLEASE_INPUT_USERNAME);
        new InputBox(this, this, tipText).show();
    }

    /**
     * 所有菜单项的单击响应方法。
     * @param menuItem  用户单击的菜单项
     * @return 事件在此被处理则返回 true，否则返回 false
     */
    @Override
    public boolean onMenuItemClick(MenuItem menuItem) {
        final int menuItemID = menuItem.getItemId();
        if (menuItemID == R.id.IDC_MENU_ITEM_LOGON) {
            this.onMenuItemLogonClicked();
        } else if (menuItemID == R.id.IDC_MENU_ITEM_REG) {
            this.onMenuItemRegClicked();
        } else if (menuItemID == R.id.IDC_MENU_ITEM_ADD_FRIEND) {
            this.onMenuItemAddFriendClicked();
        } else if (menuItemID == R.id.IDC_MENU_ITEM_MCHAT) {
            this.onMenuItemMChatClicked();
        } else if (menuItemID == R.id.IDC_MENU_ITEM_LOGOFF) {
            this.onMenuItemLogoffClicked();
        } else {
            return false;
        }
        return true;
    }

    /**
     * "离线"菜单项的单击响应方法。
     */
    private void onMenuItemLogoffClicked() {
        // 设置各种控件的状态
        this.changeState(false);

        // 清空各种列表
        mListViewUsers.clear();
        ChatActivity.clear();

        // 发送离线请求
        mClient.logoff();
    }

    /**
     * "登录"菜单项的单击响应方法。
     */
    private void onMenuItemLogonClicked() {
        new LogonDialog(this, this).show();
    }

    /**
     * "群发消息"菜单项的单击响应方法。
     */
    private void onMenuItemMChatClicked() {
        // 取消系统通知
        final NotificationManager manager = (NotificationManager)super.getSystemService(Context.NOTIFICATION_SERVICE);
        manager.cancel(Const.NOTIFICATION_ID_CHAT);

        // 生成意图
        final Intent intent = new Intent(this, ChatActivity.class);

        // 将"群发消息"保存到意图中
        intent.putExtra(Const.KEY_FRIEND_NAME, ImProtocol.MULTI_CHAT);

        // 显示聊天窗口
        super.startActivityForResult(intent, Const.UM_CHAT_C2S);
    }

    /**
     * "注册"菜单项的单击响应方法。
     */
    private void onMenuItemRegClicked() {
        final Intent intent = new Intent(this, RegActivity.class);
        super.startActivityForResult(intent, Const.RC_REG);
    }
}
